home

Load Libraries


### https://cran.r-project.org/web/packages/udpipe/vignettes/udpipe-usecase-postagging-lemmatisation.html
library(udpipe)
ud_model <- udpipe_download_model(language = "english")
library(tidyverse)
library(tidyr)
library(dplyr)
library(ggplot2)
library(ggrepel)
library(knitr)
library(tm)
library(quanteda)
library(lattice)
library(latticeExtra)
library(plotly)
library(pdp)
library(patchwork)
library(lubridate)

Load the FW functions


### CODE DIRECTLY FROM: https://burtmonroe.github.io/TextAsDataCourse/Tutorials/TADA-FightinWords.nb.html#
fwgroups <- function(dtm, groups, pair = NULL, weights = rep(1,nrow(dtm)), k.prior = .1) {
  
  weights[is.na(weights)] <- 0
  
  weights <- weights/mean(weights)
  
  zero.doc <- rowSums(dtm)==0 | weights==0
  zero.term <- colSums(dtm[!zero.doc,])==0
  
  dtm.nz <- apply(dtm[!zero.doc,!zero.term],2,"*", weights[!zero.doc])
  
  g.prior <- tcrossprod(rowSums(dtm.nz),colSums(dtm.nz))/sum(dtm.nz)
  
  # 
  
  g.posterior <- as.matrix(dtm.nz + k.prior*g.prior)
  
  groups <- groups[!zero.doc]
  groups <- droplevels(groups)
  
  g.adtm <- as.matrix(aggregate(x=g.posterior,by=list(groups=groups),FUN=sum)[,-1])
  rownames(g.adtm) <- levels(groups)
  
  g.ladtm <- log(g.adtm)
  
  g.delta <- t(scale( t(scale(g.ladtm, center=T, scale=F)), center=T, scale=F))
  
  g.adtm_w <- -sweep(g.adtm,1,rowSums(g.adtm)) # terms not w spoken by k
  g.adtm_k <- -sweep(g.adtm,2,colSums(g.adtm)) # w spoken by groups other than k
  g.adtm_kw <- sum(g.adtm) - g.adtm_w - g.adtm_k - g.adtm # total terms not w or k 
  
  g.se <- sqrt(1/g.adtm + 1/g.adtm_w + 1/g.adtm_k + 1/g.adtm_kw)
  
  g.zeta <- g.delta/g.se
  
  g.counts <- as.matrix(aggregate(x=dtm.nz, by = list(groups=groups), FUN=sum)[,-1])
  
  if (!is.null(pair)) {
    pr.delta <- t(scale( t(scale(g.ladtm[pair,], center = T, scale =F)), center=T, scale=F))
    pr.adtm_w <- -sweep(g.adtm[pair,],1,rowSums(g.adtm[pair,]))
    pr.adtm_k <- -sweep(g.adtm[pair,],2,colSums(g.adtm[pair,])) # w spoken by groups other than k
    pr.adtm_kw <- sum(g.adtm[pair,]) - pr.adtm_w - pr.adtm_k - g.adtm[pair,] # total terms not w or k
    pr.se <- sqrt(1/g.adtm[pair,] + 1/pr.adtm_w + 1/pr.adtm_k + 1/pr.adtm_kw)
    pr.zeta <- pr.delta/pr.se
    
    return(list(zeta=pr.zeta[1,], delta=pr.delta[1,],se=pr.se[1,], counts = colSums(dtm.nz), acounts = colSums(g.adtm)))
  } else {
    return(list(zeta=g.zeta,delta=g.delta,se=g.se,counts=g.counts,acounts=g.adtm))
  }
}

############## FIGHTIN' WORDS PLOTTING FUNCTION

# helper function
makeTransparent<-function(someColor, alpha=100)
{
  newColor<-col2rgb(someColor)
  apply(newColor, 2, function(curcoldata){rgb(red=curcoldata[1], green=curcoldata[2],
                                              blue=curcoldata[3],alpha=alpha, maxColorValue=255)})
}

fw.ggplot.groups <- function(fw.ch, groups.use = as.factor(rownames(fw.ch$zeta)), max.words = 50, max.countrank = 400, colorpalette=rep("black",length(groups.use)), sizescale=2, title="Comparison of Terms by Groups", subtitle = "", caption = "Group-specific terms are ordered by Fightin' Words statistic (Monroe, et al. 2008)") {
  if (is.null(dim(fw.ch$zeta))) {## two-group fw object consists of vectors, not matrices
    zetarankmat <- cbind(rank(-fw.ch$zeta),rank(fw.ch$zeta))
    colnames(zetarankmat) <- groups.use
    countrank <- rank(-(fw.ch$counts))
  } else {
    zetarankmat <- apply(-fw.ch$zeta[groups.use,],1,rank)
    countrank <- rank(-colSums(fw.ch$counts))
  }
  wideplotmat <- as_tibble(cbind(zetarankmat,countrank=countrank))
  wideplotmat$term=names(countrank)
  rankplot <- gather(wideplotmat, groups.use, zetarank, 1:ncol(zetarankmat))
  rankplot$plotsize <- sizescale*(50/(rankplot$zetarank))^(1/4)
  rankplot <- rankplot[rankplot$zetarank < max.words + 1 & rankplot$countrank<max.countrank+1,]
  rankplot$groups.use <- factor(rankplot$groups.use,levels=groups.use)
  
  p <- ggplot(rankplot, aes((nrow(rankplot)-countrank)^1, -(zetarank^1), colour=groups.use)) + 
    geom_point(show.legend=F,size=sizescale/2) + 
    theme_classic() +
    theme(axis.ticks=element_blank(), axis.text=element_blank() ) +
    ylim(-max.words,40) +
    facet_grid(groups.use ~ .) +
    geom_text_repel(aes(label = term), size = rankplot$plotsize, point.padding=.05,
                    box.padding = unit(0.20, "lines"), show.legend=F) +
    scale_colour_manual(values = alpha(colorpalette, .7)) + 
    labs(x=paste("Terms used more frequently overall -->"), y=paste("Terms used more frequently by group -->"),  title=title, subtitle=subtitle , caption = caption) 
  
}

fw.keys <- function(fw.ch,n.keys=10) {
  n.groups <- nrow(fw.ch$zeta)
  keys <- matrix("",n.keys,n.groups)
  colnames(keys) <- rownames(fw.ch$zeta)
  
  for (g in 1:n.groups) {
    keys[,g] <- names(sort(fw.ch$zeta[g,],dec=T)[1:n.keys])
  }
  keys
}

Compare Associated Press 1994-2010: Before and After “extremist”

Load and clean the data


######################################

### Text Cleaning Function

text_cleaner<-function(corpus){
  tempcorpus<-Corpus(VectorSource(corpus))
  tempcorpus<-tm_map(tempcorpus,
                    removePunctuation)
  tempcorpus<-tm_map(tempcorpus,
                    stripWhitespace)
  tempcorpus<-tm_map(tempcorpus,
                    removeNumbers)
  tempcorpus<-tm_map(tempcorpus,
                     removeWords, stopwords("english"))
  tempcorpus<-tm_map(tempcorpus, 
                    stemDocument)
  return(tempcorpus)
}

######################################

Calculate FW.

[1] 0.9900516

##################################################################

fw.extrem <- fwgroups(extrem_dtm, groups=extrem_NYT.dfm.long$Context)
Error: vector memory exhausted (limit reached?)

Get and show the top words per group by zeta.

##################################################################

fwkeys.extrem <- fw.keys(fw.extrem, n.keys=20)
cols <- rev(colnames(fwkeys.extrem))
fwkeys.extrem <- fwkeys.extrem[,cols]

##################################################################

kable(fwkeys.extrem)
Context.before Context.after
muslim group
jewish organ
rightw movement
islamic respons
member element
rrb hutu
suspect network
belong ideolog
ban militia
lrb oppos
alqaidalink view
small activ
rabin bomb
sunni sayyaf
assassin threaten
ap parti
alleg abu
outlaw attack
yitzhak alqaida
help govern

##################################################################

Plot: Comparing Words Before (in Blue), and After (in Red)

p.fw.extrem <- fw.ggplot.groups(fw.extrem,sizescale=4,max.words=200,
                                max.countrank=400,colorpalette=c("red","blue"),
                                 title = 'Comparison of Terms Before and After "Extremist"')
p.fw.extrem

Calculate Parts of speech by before and after

##################################################################

ud_model <- udpipe_load_model(ud_model$file_model)

txt <-as.character(extrem_NYT.dfm.long$context.text)

x_udp <- udpipe_annotate(ud_model, x = txt, doc_id = seq_along(txt))
x <- as.data.frame(x_udp)

x$doc_id <-as.integer(x$doc_id)


##################################################################
##################################################################

x_odd.before <- x[x$doc_id %% 2 == 1,]
x_even.after <-x[x$doc_id %% 2 == 0, ]

##################################################################

Bar Charts for Parts of Speech

Cooccurences

Cooccurences (part 2)


Corrs(x_odd.before)
Corrs(x_even.after)
NA

Extrem(ist) Fightin’ Words Over Time

library(tweenr)

TransitionTime2 <- ggproto(
  "TransitionTime2",
  TransitionTime,
  expand_panel = function (self, data, type, id, match, ease, enter, exit, params, 
                           layer_index) {
    row_time <- self$get_row_vars(data)
    if (is.null(row_time)) 
      return(data)
    data$group <- paste0(row_time$before, row_time$after)
    time <- as.integer(row_time$time)
    states <- split(data, time)
    times <- as.integer(names(states))
    nframes <- diff(times)
    nframes[1] <- nframes[1] + 1
    if (times[1] <= 1) {
      all_frames <- states[[1]]
      states <- states[-1]
    }
    else {
      all_frames <- data[0, , drop = FALSE]
      nframes <- c(times[1] - 1, nframes)
    }
    if (times[length(times)] < params$nframes) {
      states <- c(states, list(data[0, , drop = FALSE]))
      nframes <- c(nframes, params$nframes - times[length(times)])
    }
    for (i in seq_along(states)) {
      all_frames <- switch(type, point = tween_state(all_frames, 
                                                     states[[i]], ease, nframes[i], 
                                                     !!id, enter, exit), 
                           path = transform_path(all_frames, 
                                                 states[[i]], ease, nframes[i], 
                                                 !!id, enter, exit, match), 
                           polygon = transform_polygon(all_frames, 
                                                       states[[i]], ease, nframes[i], 
                                                       !!id, enter, exit, match), 
                           sf = transform_sf(all_frames, 
                                             states[[i]], ease, nframes[i], 
                                             !!id, enter, exit), 
                           stop(type, 
                                " layers not currently supported by transition_time", 
                                call. = FALSE))
    }
    true_frame <- seq(times[1], times[length(times)])
    all_frames <- all_frames[
      all_frames$.frame %in% 
        # which(true_frame > 0 & true_frame <= params$nframes),
        true_frame[which(true_frame > 0 & true_frame <= params$nframes)], # tweak line A
      , 
      drop = FALSE]
    # all_frames$.frame <- all_frames$.frame - min(all_frames$.frame) + 1 # remove line B
    all_frames$group <- paste0(all_frames$group, "<", all_frames$.frame, ">")
    all_frames$.frame <- NULL
    all_frames
  })

transition_time2 <- function (time, range = NULL) {
  time_quo <- enquo(time)
  gganimate:::require_quo(time_quo, "time")
  ggproto(NULL, TransitionTime2, 
          params = list(time_quo = time_quo, range = range))
}

Inserting image 1 at 0.00s (1%)...
Inserting image 2 at 0.10s (2%)...
Inserting image 3 at 0.20s (3%)...
Inserting image 4 at 0.30s (4%)...
Inserting image 5 at 0.40s (5%)...
Inserting image 6 at 0.50s (6%)...
Inserting image 7 at 0.60s (7%)...
Inserting image 8 at 0.70s (8%)...
Inserting image 9 at 0.80s (9%)...
Inserting image 10 at 0.90s (10%)...
Inserting image 11 at 1.00s (11%)...
Inserting image 12 at 1.10s (12%)...
Inserting image 13 at 1.20s (13%)...
Inserting image 14 at 1.30s (14%)...
Inserting image 15 at 1.40s (15%)...
Inserting image 16 at 1.50s (16%)...
Inserting image 17 at 1.60s (17%)...
Inserting image 18 at 1.70s (18%)...
Inserting image 19 at 1.80s (19%)...
Inserting image 20 at 1.90s (20%)...
Inserting image 21 at 2.00s (21%)...
Inserting image 22 at 2.10s (22%)...
Inserting image 23 at 2.20s (23%)...
Inserting image 24 at 2.30s (24%)...
Inserting image 25 at 2.40s (25%)...
Inserting image 26 at 2.50s (26%)...
Inserting image 27 at 2.60s (27%)...
Inserting image 28 at 2.70s (28%)...
Inserting image 29 at 2.80s (29%)...
Inserting image 30 at 2.90s (30%)...
Inserting image 31 at 3.00s (31%)...
Inserting image 32 at 3.10s (32%)...
Inserting image 33 at 3.20s (33%)...
Inserting image 34 at 3.30s (34%)...
Inserting image 35 at 3.40s (35%)...
Inserting image 36 at 3.50s (36%)...
Inserting image 37 at 3.60s (37%)...
Inserting image 38 at 3.70s (38%)...
Inserting image 39 at 3.80s (39%)...
Inserting image 40 at 3.90s (40%)...
Inserting image 41 at 4.00s (41%)...
Inserting image 42 at 4.10s (42%)...
Inserting image 43 at 4.20s (43%)...
Inserting image 44 at 4.30s (44%)...
Inserting image 45 at 4.40s (45%)...
Inserting image 46 at 4.50s (46%)...
Inserting image 47 at 4.60s (47%)...
Inserting image 48 at 4.70s (48%)...
Inserting image 49 at 4.80s (49%)...
Inserting image 50 at 4.90s (50%)...
Inserting image 51 at 5.00s (51%)...
Inserting image 52 at 5.10s (52%)...
Inserting image 53 at 5.20s (53%)...
Inserting image 54 at 5.30s (54%)...
Inserting image 55 at 5.40s (55%)...
Inserting image 56 at 5.50s (56%)...
Inserting image 57 at 5.60s (57%)...
Inserting image 58 at 5.70s (58%)...
Inserting image 59 at 5.80s (59%)...
Inserting image 60 at 5.90s (60%)...
Inserting image 61 at 6.00s (61%)...
Inserting image 62 at 6.10s (62%)...
Inserting image 63 at 6.20s (63%)...
Inserting image 64 at 6.30s (64%)...
Inserting image 65 at 6.40s (65%)...
Inserting image 66 at 6.50s (66%)...
Inserting image 67 at 6.60s (67%)...
Inserting image 68 at 6.70s (68%)...
Inserting image 69 at 6.80s (69%)...
Inserting image 70 at 6.90s (70%)...
Inserting image 71 at 7.00s (71%)...
Inserting image 72 at 7.10s (72%)...
Inserting image 73 at 7.20s (73%)...
Inserting image 74 at 7.30s (74%)...
Inserting image 75 at 7.40s (75%)...
Inserting image 76 at 7.50s (76%)...
Inserting image 77 at 7.60s (77%)...
Inserting image 78 at 7.70s (78%)...
Inserting image 79 at 7.80s (79%)...
Inserting image 80 at 7.90s (80%)...
Inserting image 81 at 8.00s (81%)...
Inserting image 82 at 8.10s (82%)...
Inserting image 83 at 8.20s (83%)...
Inserting image 84 at 8.30s (84%)...
Inserting image 85 at 8.40s (85%)...
Inserting image 86 at 8.50s (86%)...
Inserting image 87 at 8.60s (87%)...
Inserting image 88 at 8.70s (88%)...
Inserting image 89 at 8.80s (89%)...
Inserting image 90 at 8.90s (90%)...
Inserting image 91 at 9.00s (91%)...
Inserting image 92 at 9.10s (92%)...
Inserting image 93 at 9.20s (93%)...
Inserting image 94 at 9.30s (94%)...
Inserting image 95 at 9.40s (95%)...
Inserting image 96 at 9.50s (96%)...
Inserting image 97 at 9.60s (97%)...
Inserting image 98 at 9.70s (98%)...
Inserting image 99 at 9.80s (99%)...
Inserting image 100 at 9.90s (100%)...
Encoding to gif... done!
<ggproto object: Class EaseAes, gg>
    aes_names: 
    aesthetics: 
    default: linear
    get_ease: function
    super:  <ggproto object: Class EaseAes, gg>

Inserting image 1 at 0.00s (1%)...
Inserting image 2 at 0.10s (2%)...
Inserting image 3 at 0.20s (3%)...
Inserting image 4 at 0.30s (4%)...
Inserting image 5 at 0.40s (5%)...
Inserting image 6 at 0.50s (6%)...
Inserting image 7 at 0.60s (7%)...
Inserting image 8 at 0.70s (8%)...
Inserting image 9 at 0.80s (9%)...
Inserting image 10 at 0.90s (10%)...
Inserting image 11 at 1.00s (11%)...
Inserting image 12 at 1.10s (12%)...
Inserting image 13 at 1.20s (13%)...
Inserting image 14 at 1.30s (14%)...
Inserting image 15 at 1.40s (15%)...
Inserting image 16 at 1.50s (16%)...
Inserting image 17 at 1.60s (17%)...
Inserting image 18 at 1.70s (18%)...
Inserting image 19 at 1.80s (19%)...
Inserting image 20 at 1.90s (20%)...
Inserting image 21 at 2.00s (21%)...
Inserting image 22 at 2.10s (22%)...
Inserting image 23 at 2.20s (23%)...
Inserting image 24 at 2.30s (24%)...
Inserting image 25 at 2.40s (25%)...
Inserting image 26 at 2.50s (26%)...
Inserting image 27 at 2.60s (27%)...
Inserting image 28 at 2.70s (28%)...
Inserting image 29 at 2.80s (29%)...
Inserting image 30 at 2.90s (30%)...
Inserting image 31 at 3.00s (31%)...
Inserting image 32 at 3.10s (32%)...
Inserting image 33 at 3.20s (33%)...
Inserting image 34 at 3.30s (34%)...
Inserting image 35 at 3.40s (35%)...
Inserting image 36 at 3.50s (36%)...
Inserting image 37 at 3.60s (37%)...
Inserting image 38 at 3.70s (38%)...
Inserting image 39 at 3.80s (39%)...
Inserting image 40 at 3.90s (40%)...
Inserting image 41 at 4.00s (41%)...
Inserting image 42 at 4.10s (42%)...
Inserting image 43 at 4.20s (43%)...
Inserting image 44 at 4.30s (44%)...
Inserting image 45 at 4.40s (45%)...
Inserting image 46 at 4.50s (46%)...
Inserting image 47 at 4.60s (47%)...
Inserting image 48 at 4.70s (48%)...
Inserting image 49 at 4.80s (49%)...
Inserting image 50 at 4.90s (50%)...
Inserting image 51 at 5.00s (51%)...
Inserting image 52 at 5.10s (52%)...
Inserting image 53 at 5.20s (53%)...
Inserting image 54 at 5.30s (54%)...
Inserting image 55 at 5.40s (55%)...
Inserting image 56 at 5.50s (56%)...
Inserting image 57 at 5.60s (57%)...
Inserting image 58 at 5.70s (58%)...
Inserting image 59 at 5.80s (59%)...
Inserting image 60 at 5.90s (60%)...
Inserting image 61 at 6.00s (61%)...
Inserting image 62 at 6.10s (62%)...
Inserting image 63 at 6.20s (63%)...
Inserting image 64 at 6.30s (64%)...
Inserting image 65 at 6.40s (65%)...
Inserting image 66 at 6.50s (66%)...
Inserting image 67 at 6.60s (67%)...
Inserting image 68 at 6.70s (68%)...
Inserting image 69 at 6.80s (69%)...
Inserting image 70 at 6.90s (70%)...
Inserting image 71 at 7.00s (71%)...
Inserting image 72 at 7.10s (72%)...
Inserting image 73 at 7.20s (73%)...
Inserting image 74 at 7.30s (74%)...
Inserting image 75 at 7.40s (75%)...
Inserting image 76 at 7.50s (76%)...
Inserting image 77 at 7.60s (77%)...
Inserting image 78 at 7.70s (78%)...
Inserting image 79 at 7.80s (79%)...
Inserting image 80 at 7.90s (80%)...
Inserting image 81 at 8.00s (81%)...
Inserting image 82 at 8.10s (82%)...
Inserting image 83 at 8.20s (83%)...
Inserting image 84 at 8.30s (84%)...
Inserting image 85 at 8.40s (85%)...
Inserting image 86 at 8.50s (86%)...
Inserting image 87 at 8.60s (87%)...
Inserting image 88 at 8.70s (88%)...
Inserting image 89 at 8.80s (89%)...
Inserting image 90 at 8.90s (90%)...
Inserting image 91 at 9.00s (91%)...
Inserting image 92 at 9.10s (92%)...
Inserting image 93 at 9.20s (93%)...
Inserting image 94 at 9.30s (94%)...
Inserting image 95 at 9.40s (95%)...
Inserting image 96 at 9.50s (96%)...
Inserting image 97 at 9.60s (97%)...
Inserting image 98 at 9.70s (98%)...
Inserting image 99 at 9.80s (99%)...
Inserting image 100 at 9.90s (100%)...
Encoding to gif... done!
<ggproto object: Class EaseAes, gg>
    aes_names: 
    aesthetics: 
    default: linear
    get_ease: function
    super:  <ggproto object: Class EaseAes, gg>

Inserting image 1 at 0.00s (1%)...
Inserting image 2 at 0.10s (2%)...
Inserting image 3 at 0.20s (3%)...
Inserting image 4 at 0.30s (4%)...
Inserting image 5 at 0.40s (5%)...
Inserting image 6 at 0.50s (6%)...
Inserting image 7 at 0.60s (7%)...
Inserting image 8 at 0.70s (8%)...
Inserting image 9 at 0.80s (9%)...
Inserting image 10 at 0.90s (10%)...
Inserting image 11 at 1.00s (11%)...
Inserting image 12 at 1.10s (12%)...
Inserting image 13 at 1.20s (13%)...
Inserting image 14 at 1.30s (14%)...
Inserting image 15 at 1.40s (15%)...
Inserting image 16 at 1.50s (16%)...
Inserting image 17 at 1.60s (17%)...
Inserting image 18 at 1.70s (18%)...
Inserting image 19 at 1.80s (19%)...
Inserting image 20 at 1.90s (20%)...
Inserting image 21 at 2.00s (21%)...
Inserting image 22 at 2.10s (22%)...
Inserting image 23 at 2.20s (23%)...
Inserting image 24 at 2.30s (24%)...
Inserting image 25 at 2.40s (25%)...
Inserting image 26 at 2.50s (26%)...
Inserting image 27 at 2.60s (27%)...
Inserting image 28 at 2.70s (28%)...
Inserting image 29 at 2.80s (29%)...
Inserting image 30 at 2.90s (30%)...
Inserting image 31 at 3.00s (31%)...
Inserting image 32 at 3.10s (32%)...
Inserting image 33 at 3.20s (33%)...
Inserting image 34 at 3.30s (34%)...
Inserting image 35 at 3.40s (35%)...
Inserting image 36 at 3.50s (36%)...
Inserting image 37 at 3.60s (37%)...
Inserting image 38 at 3.70s (38%)...
Inserting image 39 at 3.80s (39%)...
Inserting image 40 at 3.90s (40%)...
Inserting image 41 at 4.00s (41%)...
Inserting image 42 at 4.10s (42%)...
Inserting image 43 at 4.20s (43%)...
Inserting image 44 at 4.30s (44%)...
Inserting image 45 at 4.40s (45%)...
Inserting image 46 at 4.50s (46%)...
Inserting image 47 at 4.60s (47%)...
Inserting image 48 at 4.70s (48%)...
Inserting image 49 at 4.80s (49%)...
Inserting image 50 at 4.90s (50%)...
Inserting image 51 at 5.00s (51%)...
Inserting image 52 at 5.10s (52%)...
Inserting image 53 at 5.20s (53%)...
Inserting image 54 at 5.30s (54%)...
Inserting image 55 at 5.40s (55%)...
Inserting image 56 at 5.50s (56%)...
Inserting image 57 at 5.60s (57%)...
Inserting image 58 at 5.70s (58%)...
Inserting image 59 at 5.80s (59%)...
Inserting image 60 at 5.90s (60%)...
Inserting image 61 at 6.00s (61%)...
Inserting image 62 at 6.10s (62%)...
Inserting image 63 at 6.20s (63%)...
Inserting image 64 at 6.30s (64%)...
Inserting image 65 at 6.40s (65%)...
Inserting image 66 at 6.50s (66%)...
Inserting image 67 at 6.60s (67%)...
Inserting image 68 at 6.70s (68%)...
Inserting image 69 at 6.80s (69%)...
Inserting image 70 at 6.90s (70%)...
Inserting image 71 at 7.00s (71%)...
Inserting image 72 at 7.10s (72%)...
Inserting image 73 at 7.20s (73%)...
Inserting image 74 at 7.30s (74%)...
Inserting image 75 at 7.40s (75%)...
Inserting image 76 at 7.50s (76%)...
Inserting image 77 at 7.60s (77%)...
Inserting image 78 at 7.70s (78%)...
Inserting image 79 at 7.80s (79%)...
Inserting image 80 at 7.90s (80%)...
Inserting image 81 at 8.00s (81%)...
Inserting image 82 at 8.10s (82%)...
Inserting image 83 at 8.20s (83%)...
Inserting image 84 at 8.30s (84%)...
Inserting image 85 at 8.40s (85%)...
Inserting image 86 at 8.50s (86%)...
Inserting image 87 at 8.60s (87%)...
Inserting image 88 at 8.70s (88%)...
Inserting image 89 at 8.80s (89%)...
Inserting image 90 at 8.90s (90%)...
Inserting image 91 at 9.00s (91%)...
Inserting image 92 at 9.10s (92%)...
Inserting image 93 at 9.20s (93%)...
Inserting image 94 at 9.30s (94%)...
Inserting image 95 at 9.40s (95%)...
Inserting image 96 at 9.50s (96%)...
Inserting image 97 at 9.60s (97%)...
Inserting image 98 at 9.70s (98%)...
Inserting image 99 at 9.80s (99%)...
Inserting image 100 at 9.90s (100%)...
Encoding to gif... done!
<ggproto object: Class EaseAes, gg>
    aes_names: 
    aesthetics: 
    default: linear
    get_ease: function
    super:  <ggproto object: Class EaseAes, gg>

home

LS0tCnRpdGxlOiAiRXh0cmVtKGlzdCkgRmlnaHRpbicgV29yZHMiCmF1dGhvcjogIkJyZWFubmEgRS4gR3JlZW4iCnN1YnRpdGxlOiAnQXNzb2NpYXRlZCBQcmVzcyAxOTk0LTIwMTA6IEtleXdvcmQ6IkV4dHJlbWlzdCInCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdGhlbWU6IHVuaXRlZAogICAgdG9jOiB5ZXMKLS0tCgpbaG9tZV0oaHR0cHM6Ly9icmVncmVlbi5naXRodWIuaW8vKQoKIyMgTG9hZCBMaWJyYXJpZXMKCmBgYHtyIGxvYWQgbGlicmFyaWVzLCByZXN1bHRzPSdoaWRlJ30KCiMjIyBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdWRwaXBlL3ZpZ25ldHRlcy91ZHBpcGUtdXNlY2FzZS1wb3N0YWdnaW5nLWxlbW1hdGlzYXRpb24uaHRtbApsaWJyYXJ5KHVkcGlwZSkKdWRfbW9kZWwgPC0gdWRwaXBlX2Rvd25sb2FkX21vZGVsKGxhbmd1YWdlID0gImVuZ2xpc2giKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KHF1YW50ZWRhKQpsaWJyYXJ5KGxhdHRpY2UpCmxpYnJhcnkobGF0dGljZUV4dHJhKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShwZHApCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKCmBgYAoKIyMgTG9hZCB0aGUgRlcgZnVuY3Rpb25zCgpgYGB7ciBsb2FkX2Z3X2Z1bmN0aW9uc30KCiMjIyBDT0RFIERJUkVDVExZIEZST006IGh0dHBzOi8vYnVydG1vbnJvZS5naXRodWIuaW8vVGV4dEFzRGF0YUNvdXJzZS9UdXRvcmlhbHMvVEFEQS1GaWdodGluV29yZHMubmIuaHRtbCMKZndncm91cHMgPC0gZnVuY3Rpb24oZHRtLCBncm91cHMsIHBhaXIgPSBOVUxMLCB3ZWlnaHRzID0gcmVwKDEsbnJvdyhkdG0pKSwgay5wcmlvciA9IC4xKSB7CiAgCiAgd2VpZ2h0c1tpcy5uYSh3ZWlnaHRzKV0gPC0gMAogIAogIHdlaWdodHMgPC0gd2VpZ2h0cy9tZWFuKHdlaWdodHMpCiAgCiAgemVyby5kb2MgPC0gcm93U3VtcyhkdG0pPT0wIHwgd2VpZ2h0cz09MAogIHplcm8udGVybSA8LSBjb2xTdW1zKGR0bVshemVyby5kb2MsXSk9PTAKICAKICBkdG0ubnogPC0gYXBwbHkoZHRtWyF6ZXJvLmRvYywhemVyby50ZXJtXSwyLCIqIiwgd2VpZ2h0c1shemVyby5kb2NdKQogIAogIGcucHJpb3IgPC0gdGNyb3NzcHJvZChyb3dTdW1zKGR0bS5ueiksY29sU3VtcyhkdG0ubnopKS9zdW0oZHRtLm56KQogIAogICMgCiAgCiAgZy5wb3N0ZXJpb3IgPC0gYXMubWF0cml4KGR0bS5ueiArIGsucHJpb3IqZy5wcmlvcikKICAKICBncm91cHMgPC0gZ3JvdXBzWyF6ZXJvLmRvY10KICBncm91cHMgPC0gZHJvcGxldmVscyhncm91cHMpCiAgCiAgZy5hZHRtIDwtIGFzLm1hdHJpeChhZ2dyZWdhdGUoeD1nLnBvc3RlcmlvcixieT1saXN0KGdyb3Vwcz1ncm91cHMpLEZVTj1zdW0pWywtMV0pCiAgcm93bmFtZXMoZy5hZHRtKSA8LSBsZXZlbHMoZ3JvdXBzKQogIAogIGcubGFkdG0gPC0gbG9nKGcuYWR0bSkKICAKICBnLmRlbHRhIDwtIHQoc2NhbGUoIHQoc2NhbGUoZy5sYWR0bSwgY2VudGVyPVQsIHNjYWxlPUYpKSwgY2VudGVyPVQsIHNjYWxlPUYpKQogIAogIGcuYWR0bV93IDwtIC1zd2VlcChnLmFkdG0sMSxyb3dTdW1zKGcuYWR0bSkpICMgdGVybXMgbm90IHcgc3Bva2VuIGJ5IGsKICBnLmFkdG1fayA8LSAtc3dlZXAoZy5hZHRtLDIsY29sU3VtcyhnLmFkdG0pKSAjIHcgc3Bva2VuIGJ5IGdyb3VwcyBvdGhlciB0aGFuIGsKICBnLmFkdG1fa3cgPC0gc3VtKGcuYWR0bSkgLSBnLmFkdG1fdyAtIGcuYWR0bV9rIC0gZy5hZHRtICMgdG90YWwgdGVybXMgbm90IHcgb3IgayAKICAKICBnLnNlIDwtIHNxcnQoMS9nLmFkdG0gKyAxL2cuYWR0bV93ICsgMS9nLmFkdG1fayArIDEvZy5hZHRtX2t3KQogIAogIGcuemV0YSA8LSBnLmRlbHRhL2cuc2UKICAKICBnLmNvdW50cyA8LSBhcy5tYXRyaXgoYWdncmVnYXRlKHg9ZHRtLm56LCBieSA9IGxpc3QoZ3JvdXBzPWdyb3VwcyksIEZVTj1zdW0pWywtMV0pCiAgCiAgaWYgKCFpcy5udWxsKHBhaXIpKSB7CiAgICBwci5kZWx0YSA8LSB0KHNjYWxlKCB0KHNjYWxlKGcubGFkdG1bcGFpcixdLCBjZW50ZXIgPSBULCBzY2FsZSA9RikpLCBjZW50ZXI9VCwgc2NhbGU9RikpCiAgICBwci5hZHRtX3cgPC0gLXN3ZWVwKGcuYWR0bVtwYWlyLF0sMSxyb3dTdW1zKGcuYWR0bVtwYWlyLF0pKQogICAgcHIuYWR0bV9rIDwtIC1zd2VlcChnLmFkdG1bcGFpcixdLDIsY29sU3VtcyhnLmFkdG1bcGFpcixdKSkgIyB3IHNwb2tlbiBieSBncm91cHMgb3RoZXIgdGhhbiBrCiAgICBwci5hZHRtX2t3IDwtIHN1bShnLmFkdG1bcGFpcixdKSAtIHByLmFkdG1fdyAtIHByLmFkdG1fayAtIGcuYWR0bVtwYWlyLF0gIyB0b3RhbCB0ZXJtcyBub3QgdyBvciBrCiAgICBwci5zZSA8LSBzcXJ0KDEvZy5hZHRtW3BhaXIsXSArIDEvcHIuYWR0bV93ICsgMS9wci5hZHRtX2sgKyAxL3ByLmFkdG1fa3cpCiAgICBwci56ZXRhIDwtIHByLmRlbHRhL3ByLnNlCiAgICAKICAgIHJldHVybihsaXN0KHpldGE9cHIuemV0YVsxLF0sIGRlbHRhPXByLmRlbHRhWzEsXSxzZT1wci5zZVsxLF0sIGNvdW50cyA9IGNvbFN1bXMoZHRtLm56KSwgYWNvdW50cyA9IGNvbFN1bXMoZy5hZHRtKSkpCiAgfSBlbHNlIHsKICAgIHJldHVybihsaXN0KHpldGE9Zy56ZXRhLGRlbHRhPWcuZGVsdGEsc2U9Zy5zZSxjb3VudHM9Zy5jb3VudHMsYWNvdW50cz1nLmFkdG0pKQogIH0KfQoKIyMjIyMjIyMjIyMjIyMgRklHSFRJTicgV09SRFMgUExPVFRJTkcgRlVOQ1RJT04KCiMgaGVscGVyIGZ1bmN0aW9uCm1ha2VUcmFuc3BhcmVudDwtZnVuY3Rpb24oc29tZUNvbG9yLCBhbHBoYT0xMDApCnsKICBuZXdDb2xvcjwtY29sMnJnYihzb21lQ29sb3IpCiAgYXBwbHkobmV3Q29sb3IsIDIsIGZ1bmN0aW9uKGN1cmNvbGRhdGEpe3JnYihyZWQ9Y3VyY29sZGF0YVsxXSwgZ3JlZW49Y3VyY29sZGF0YVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJsdWU9Y3VyY29sZGF0YVszXSxhbHBoYT1hbHBoYSwgbWF4Q29sb3JWYWx1ZT0yNTUpfSkKfQoKZncuZ2dwbG90Lmdyb3VwcyA8LSBmdW5jdGlvbihmdy5jaCwgZ3JvdXBzLnVzZSA9IGFzLmZhY3Rvcihyb3duYW1lcyhmdy5jaCR6ZXRhKSksIG1heC53b3JkcyA9IDUwLCBtYXguY291bnRyYW5rID0gNDAwLCBjb2xvcnBhbGV0dGU9cmVwKCJibGFjayIsbGVuZ3RoKGdyb3Vwcy51c2UpKSwgc2l6ZXNjYWxlPTIsIHRpdGxlPSJDb21wYXJpc29uIG9mIFRlcm1zIGJ5IEdyb3VwcyIsIHN1YnRpdGxlID0gIiIsIGNhcHRpb24gPSAiR3JvdXAtc3BlY2lmaWMgdGVybXMgYXJlIG9yZGVyZWQgYnkgRmlnaHRpbicgV29yZHMgc3RhdGlzdGljIChNb25yb2UsIGV0IGFsLiAyMDA4KSIpIHsKICBpZiAoaXMubnVsbChkaW0oZncuY2gkemV0YSkpKSB7IyMgdHdvLWdyb3VwIGZ3IG9iamVjdCBjb25zaXN0cyBvZiB2ZWN0b3JzLCBub3QgbWF0cmljZXMKICAgIHpldGFyYW5rbWF0IDwtIGNiaW5kKHJhbmsoLWZ3LmNoJHpldGEpLHJhbmsoZncuY2gkemV0YSkpCiAgICBjb2xuYW1lcyh6ZXRhcmFua21hdCkgPC0gZ3JvdXBzLnVzZQogICAgY291bnRyYW5rIDwtIHJhbmsoLShmdy5jaCRjb3VudHMpKQogIH0gZWxzZSB7CiAgICB6ZXRhcmFua21hdCA8LSBhcHBseSgtZncuY2gkemV0YVtncm91cHMudXNlLF0sMSxyYW5rKQogICAgY291bnRyYW5rIDwtIHJhbmsoLWNvbFN1bXMoZncuY2gkY291bnRzKSkKICB9CiAgd2lkZXBsb3RtYXQgPC0gYXNfdGliYmxlKGNiaW5kKHpldGFyYW5rbWF0LGNvdW50cmFuaz1jb3VudHJhbmspKQogIHdpZGVwbG90bWF0JHRlcm09bmFtZXMoY291bnRyYW5rKQogIHJhbmtwbG90IDwtIGdhdGhlcih3aWRlcGxvdG1hdCwgZ3JvdXBzLnVzZSwgemV0YXJhbmssIDE6bmNvbCh6ZXRhcmFua21hdCkpCiAgcmFua3Bsb3QkcGxvdHNpemUgPC0gc2l6ZXNjYWxlKig1MC8ocmFua3Bsb3QkemV0YXJhbmspKV4oMS80KQogIHJhbmtwbG90IDwtIHJhbmtwbG90W3JhbmtwbG90JHpldGFyYW5rIDwgbWF4LndvcmRzICsgMSAmIHJhbmtwbG90JGNvdW50cmFuazxtYXguY291bnRyYW5rKzEsXQogIHJhbmtwbG90JGdyb3Vwcy51c2UgPC0gZmFjdG9yKHJhbmtwbG90JGdyb3Vwcy51c2UsbGV2ZWxzPWdyb3Vwcy51c2UpCiAgCiAgcCA8LSBnZ3Bsb3QocmFua3Bsb3QsIGFlcygobnJvdyhyYW5rcGxvdCktY291bnRyYW5rKV4xLCAtKHpldGFyYW5rXjEpLCBjb2xvdXI9Z3JvdXBzLnVzZSkpICsgCiAgICBnZW9tX3BvaW50KHNob3cubGVnZW5kPUYsc2l6ZT1zaXplc2NhbGUvMikgKyAKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0PWVsZW1lbnRfYmxhbmsoKSApICsKICAgIHlsaW0oLW1heC53b3Jkcyw0MCkgKwogICAgZmFjZXRfZ3JpZChncm91cHMudXNlIH4gLikgKwogICAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IHRlcm0pLCBzaXplID0gcmFua3Bsb3QkcGxvdHNpemUsIHBvaW50LnBhZGRpbmc9LjA1LAogICAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gdW5pdCgwLjIwLCAibGluZXMiKSwgc2hvdy5sZWdlbmQ9RikgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBhbHBoYShjb2xvcnBhbGV0dGUsIC43KSkgKyAKICAgIGxhYnMoeD1wYXN0ZSgiVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgb3ZlcmFsbCAtLT4iKSwgeT1wYXN0ZSgiVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgYnkgZ3JvdXAgLS0+IiksICB0aXRsZT10aXRsZSwgc3VidGl0bGU9c3VidGl0bGUgLCBjYXB0aW9uID0gY2FwdGlvbikgCiAgCn0KCmZ3LmtleXMgPC0gZnVuY3Rpb24oZncuY2gsbi5rZXlzPTEwKSB7CiAgbi5ncm91cHMgPC0gbnJvdyhmdy5jaCR6ZXRhKQogIGtleXMgPC0gbWF0cml4KCIiLG4ua2V5cyxuLmdyb3VwcykKICBjb2xuYW1lcyhrZXlzKSA8LSByb3duYW1lcyhmdy5jaCR6ZXRhKQogIAogIGZvciAoZyBpbiAxOm4uZ3JvdXBzKSB7CiAgICBrZXlzWyxnXSA8LSBuYW1lcyhzb3J0KGZ3LmNoJHpldGFbZyxdLGRlYz1UKVsxOm4ua2V5c10pCiAgfQogIGtleXMKfQpgYGAKCgojIyBDb21wYXJlIEFzc29jaWF0ZWQgUHJlc3MgMTk5NC0yMDEwOiBCZWZvcmUgYW5kIEFmdGVyICJleHRyZW1pc3QiCgoqTG9hZCBhbmQgY2xlYW4gdGhlIGRhdGEqCgogICogdG8gc3RyaW5nICYgbG93ZXIgdGV4dAogICogcGl2b3QgdG8gbG9uZyBmb3JtYXQKICAqIGFwcGx5IHRleHRfY2xlYW5lciB0byBvbmUgY29sdW1uICJjb250ZXh0LnRleHQiCgpgYGB7cn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIyMgVGV4dCBDbGVhbmluZyBGdW5jdGlvbgoKdGV4dF9jbGVhbmVyPC1mdW5jdGlvbihjb3JwdXMpewogIHRlbXBjb3JwdXM8LUNvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzKSkKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICByZW1vdmVQdW5jdHVhdGlvbikKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICBzdHJpcFdoaXRlc3BhY2UpCiAgdGVtcGNvcnB1czwtdG1fbWFwKHRlbXBjb3JwdXMsCiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlTnVtYmVycykKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQogIHRlbXBjb3JwdXM8LXRtX21hcCh0ZW1wY29ycHVzLCAKICAgICAgICAgICAgICAgICAgICBzdGVtRG9jdW1lbnQpCiAgcmV0dXJuKHRlbXBjb3JwdXMpCn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpgYGAKCmBgYHtyIGNsZWFuX3RleHQsIGVjaG89RkFMU0UsIHJlc3VsdHM9IEZBTFNFfQoKZXh0cmVtX0FQLmRmbSA8LSByZWFkLmRlbGltKCJleHRyZW1pc3RfOTQxMF9BUC50eHQiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQpleHRyZW1fQVAuZGZtJHB1YmRhdGUgPSBzdWJzdHIoZXh0cmVtX0FQLmRmbSRUZXh0LklELDksMTYpCmV4dHJlbV9BUC5kZm0kcHViZGF0ZSA8LSBhcy5QT1NJWGN0KGV4dHJlbV9BUC5kZm0kcHViZGF0ZSwgZm9ybWF0ID0gIiVZJW0lZCIpCmV4dHJlbV9BUC5kZm0kcHViZGF0ZSA8LSBhcy5EYXRlKGV4dHJlbV9BUC5kZm0kcHViZGF0ZSwgZm9ybWF0PSIlWS0lbS0lZCIpCmV4dHJlbV9BcC5kZm0kcHVieWVhciA8LSB5ZWFyKGV4dHJlbV9BUC5kZm0kcHViZGF0ZSkKCiMgZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5iZWZvcmUgPSBsYXBwbHkoZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5iZWZvcmUsIHRvU3RyaW5nKQojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlID0gbGFwcGx5KGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlLCB0b2xvd2VyKQojIAojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYWZ0ZXIgPSBsYXBwbHkoZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5hZnRlciwgdG9TdHJpbmcpCiMgZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5hZnRlciA9IGxhcHBseShleHRyZW1fTllULmRmbSRDb250ZXh0LmFmdGVyLCB0b2xvd2VyKQoKZXh0cmVtX0FQLmRmbSA8LSBleHRyZW1fQVAuZGZtICU+JSBkaXN0aW5jdChDb250ZXh0LmJlZm9yZSwgLmtlZXBfYWxsID0gVFJVRSkKCmV4dHJlbV9BUC5kZm0ubG9uZyA8LSBwaXZvdF9sb25nZXIoZXh0cmVtX0FQLmRmbSwgY29scz1jKENvbnRleHQuYmVmb3JlLCBDb250ZXh0LmFmdGVyKSwgbmFtZXNfdG8gPSAiQ29udGV4dCIsIHZhbHVlc190byA9ICJjb250ZXh0LnRleHQiKQoKZXh0cmVtX0FQLmRmbS5sb25nJENvbnRleHQgPC0gYXMuZmFjdG9yKGV4dHJlbV9BUC5kZm0ubG9uZyRDb250ZXh0KQoKZXh0cmVtZWNvcnB1cyA8LXRleHRfY2xlYW5lcihleHRyZW1fQVAuZGZtLmxvbmckY29udGV4dC50ZXh0KQoKYGBgCgoKQ2FsY3VsYXRlIEZXLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwplIDwtIGRmbShleHRyZW1lY29ycHVzJGNvbnRlbnQpCm1lc3NhZ2UoZGltKGUpKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgplIDwtIGRmbV9zZWxlY3QoZSwgcGF0dGVybiA9IHN0b3B3b3JkcygiZW5nbGlzaCIpLCBzZWxlY3Rpb24gPSAicmVtb3ZlIikKZSA8LSBkZm1fc2VsZWN0KGUsIG1pbl9uY2hhciA9IDIpCmUgPC0gZGZtX3RyaW0oZSwgbWluX3Rlcm1mcmVxID0gMTAwLCBtaW5fZG9jZnJlcSA9IC4wNSwgdmVyYm9zZT1UUlVFKQoKbWVzc2FnZShkaW0oZSkpCm1lc3NhZ2Uoc3BhcnNpdHkoZSkpCnNwYXJzaXR5KGUpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmV4dHJlbV9kdG0gPC0gY29udmVydChlLCB0bz0nZGF0YS5mcmFtZScpCmV4dHJlbV9kdG0gPC0gZXh0cmVtX2R0bVstYygxKV0KdyA8LSB3aGljaCggc2FwcGx5KGV4dHJlbV9kdG0sIGNsYXNzICkgPT0gJ2NoYXJhY3RlcicgKQoKYGBgCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpmdy5leHRyZW0gPC0gZndncm91cHMoZXh0cmVtX2R0bSwgZ3JvdXBzPWV4dHJlbV9BUC5kZm0ubG9uZyRDb250ZXh0KQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgptZXNzYWdlKHJtKGV4dHJlbV9kdG0pKQptZXNzYWdlKHJtKGUpKQoKYGBgCgoKR2V0IGFuZCBzaG93IHRoZSB0b3Agd29yZHMgcGVyIGdyb3VwIGJ5IHpldGEuCgpgYGB7ciBlY2hvPVRSVUV9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKZndrZXlzLmV4dHJlbSA8LSBmdy5rZXlzKGZ3LmV4dHJlbSwgbi5rZXlzPTIwKQpjb2xzIDwtIHJldihjb2xuYW1lcyhmd2tleXMuZXh0cmVtKSkKZndrZXlzLmV4dHJlbSA8LSBmd2tleXMuZXh0cmVtWyxjb2xzXQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgprYWJsZShmd2tleXMuZXh0cmVtKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpgYGAKCipQbG90OiBDb21wYXJpbmcgV29yZHMgQmVmb3JlIChpbiBCbHVlKSwgYW5kIEFmdGVyIChpbiBSZWQpKgoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTR9CnAuZncuZXh0cmVtIDwtIGZ3LmdncGxvdC5ncm91cHMoZncuZXh0cmVtLHNpemVzY2FsZT00LG1heC53b3Jkcz0yMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4LmNvdW50cmFuaz00MDAsY29sb3JwYWxldHRlPWMoInJlZCIsImJsdWUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAnQ29tcGFyaXNvbiBvZiBUZXJtcyBCZWZvcmUgYW5kIEFmdGVyICJFeHRyZW1pc3QiJykKcC5mdy5leHRyZW0KCmBgYAoKIyMgQ2FsY3VsYXRlIFBhcnRzIG9mIHNwZWVjaCBieSBiZWZvcmUgYW5kIGFmdGVyCgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKdWRfbW9kZWwgPC0gdWRwaXBlX2xvYWRfbW9kZWwodWRfbW9kZWwkZmlsZV9tb2RlbCkKCnR4dCA8LWFzLmNoYXJhY3RlcihleHRyZW1fQVAuZGZtLmxvbmckY29udGV4dC50ZXh0KQoKeF91ZHAgPC0gdWRwaXBlX2Fubm90YXRlKHVkX21vZGVsLCB4ID0gdHh0LCBkb2NfaWQgPSBzZXFfYWxvbmcodHh0KSkKeCA8LSBhcy5kYXRhLmZyYW1lKHhfdWRwKQoKeCRkb2NfaWQgPC1hcy5pbnRlZ2VyKHgkZG9jX2lkKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKCmBgYAoKYGBge3IsIHJlc3VsdHM9J2hpZGUnfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCnhfb2RkLmJlZm9yZSA8LSB4W3gkZG9jX2lkICUlIDIgPT0gMSxdCnhfZXZlbi5hZnRlciA8LXhbeCRkb2NfaWQgJSUgMiA9PSAwLCBdCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmBgYAoKYGBge3IgYmFyY2hhcnRmdW5jdHMsIGVjaG89RkFMU0V9CgojIyBVTklWRVJTQUwgUG9TClVQT1NfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIHN0YXRzMSA8LSB0eHRfZnJlcShkZjEkdXBvcykKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5LCBsZXZlbHMgPSByZXYoc3RhdHMxJGtleSkpCiAgCiAgc3RhdHMyIDwtIHR4dF9mcmVxKGRmMiR1cG9zKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXksIGxldmVscyA9IHJldihzdGF0czIka2V5KSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBzdGF0czEsIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICBtYWluID0gIlVQT1MgKFVuaXZlcnNhbCBQYXJ0cyBvZiBTcGVlY2gpXG4gZnJlcXVlbmN5IG9mIG9jY3VycmVuY2U6IEJFRk9SRSB2cyBBRlRFUiIsIAogICAgICAgICB4bGFiID0gIkZyZXEiKSwgCiAgICBiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gc3RhdHMyLCBjb2wgPSAgJ3NreWJsdWUnLAogICAgICAgICB4bGFiID0gIkZyZXEiKSkKCn0KCgojIyBOT1VOUwpOT1VOU19iYXJjaGFydCA8LSBmdW5jdGlvbihkZjEsIGRmMil7CiAgCiAgc3RhdHMxIDwtIHN1YnNldChkZjEsIHVwb3MgJWluJSBjKCJOT1VOIikpIAogIHN0YXRzMSA8LSB0eHRfZnJlcShzdGF0czEkdG9rZW4pCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXkpKQogIAogIHN0YXRzMiA8LSBzdWJzZXQoZGYyLCB1cG9zICVpbiUgYygiTk9VTiIpKSAKICBzdGF0czIgPC0gdHh0X2ZyZXEoc3RhdHMyJHRva2VuKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXksIGxldmVscyA9IHJldihzdGF0czIka2V5KSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJNb3N0IG9jY3VycmluZyBub3VuczogQkVGT1JFIHZzIEFGVEVSIiwgeGxhYiA9ICJGcmVxIiksCiAgICAgIGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMiwgMjApLCBjb2wgPSAic2t5Ymx1ZSIsIAogICAgICAgICAgICB4bGFiID0gIkZyZXEiKSkKfQoKIyMgQURKRUNUSVZFUwpBREpfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIHN0YXRzMSA8LSBzdWJzZXQoZGYxLCB1cG9zICVpbiUgYygiQURKIikpIAogIHN0YXRzMSA8LSB0eHRfZnJlcShzdGF0czEkdG9rZW4pCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXkpKQogIAogIHN0YXRzMiA8LSBzdWJzZXQoZGYyLCB1cG9zICVpbiUgYygiQURKIikpIAogIHN0YXRzMiA8LSB0eHRfZnJlcShzdGF0czIkdG9rZW4pCiAgc3RhdHMyJGtleSA8LSBmYWN0b3Ioc3RhdHMyJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXkpKQogIAogIGMoYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMxLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIk1vc3Qgb2NjdXJyaW5nIGFkamVjdGl2ZXM6IEJFRk9SRSB2cyBBRlRFUiIsIHhsYWIgPSAiRnJlcSIpLAogICAgICBiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gaGVhZChzdGF0czIsIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgeGxhYiA9ICJGcmVxIikpCn0KCiMjIFVzaW5nIFJBS0UgdG8gZmluZCBrZXl3b3JkcwpSQUtFX0tXX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSxkZjIpewogIAogIHN0YXRzMSA8LSBrZXl3b3Jkc19yYWtlKHggPSBkZjEsIHRlcm0gPSAibGVtbWEiLCBncm91cCA9ICJkb2NfaWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGV2YW50ID0gZGYxJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMxJGtleXdvcmQpKQogIAogIHN0YXRzMiA8LSBrZXl3b3Jkc19yYWtlKHggPSBkZjIsIHRlcm0gPSAibGVtbWEiLCBncm91cCA9ICJkb2NfaWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGV2YW50ID0gZGYyJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleXdvcmQpKQogIAogIAogIGMoYmFyY2hhcnQoa2V5IH4gcmFrZSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMSwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIktleXdvcmRzIGlkZW50aWZpZWQgYnkgUkFLRTogQkVGT1JFIHZzIEFGVEVSIiwgCiAgICAgICAgICAgeGxhYiA9ICJSYWtlIiksCiAgICBiYXJjaGFydChrZXkgfiByYWtlLCBkYXRhID0gaGVhZChzdWJzZXQoc3RhdHMyLCBmcmVxID4gMyksIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgICB4bGFiID0gIlJha2UiKSkKfQoKIyMgVXNpbmcgUG9pbnR3aXNlIE11dHVhbCBJbmZvcm1hdGlvbiBDb2xsb2NhdGlvbnMKUFdJX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICBkZjEkd29yZCA8LSB0b2xvd2VyKGRmMSR0b2tlbikKICBzdGF0czEgPC0ga2V5d29yZHNfY29sbG9jYXRpb24oeCA9IGRmMSwgdGVybSA9ICJ3b3JkIiwgZ3JvdXAgPSAiZG9jX2lkIikKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXl3b3JkKSkKICAKICBkZjIkd29yZCA8LSB0b2xvd2VyKGRmMiR0b2tlbikKICBzdGF0czIgPC0ga2V5d29yZHNfY29sbG9jYXRpb24oeCA9IGRmMiwgdGVybSA9ICJ3b3JkIiwgZ3JvdXAgPSAiZG9jX2lkIikKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXl3b3JkKSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IHBtaSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMSwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIktleXdvcmRzIGlkZW50aWZpZWQgYnkgUE1JIENvbGxvY2F0aW9uOiBCRUZPUkUgdnMgQUZURVIiLCAKICAgICAgICAgICB4bGFiID0gIlBNSSAoUG9pbnR3aXNlIE11dHVhbCBJbmZvcm1hdGlvbikiKSwKICAgICAgYmFyY2hhcnQoa2V5IH4gcG1pLCBkYXRhID0gaGVhZChzdWJzZXQoc3RhdHMyLCBmcmVxID4gMyksIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgICB4bGFiID0gIlBNSSAoUG9pbnR3aXNlIE11dHVhbCBJbmZvcm1hdGlvbikiKSkKfQoKIyMgVXNpbmcgYSBzZXF1ZW5jZSBvZiBQT1MgdGFncyAobm91biBwaHJhc2VzIC8gdmVyYiBwaHJhc2VzKQpQT1NfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIGRmMSRwaHJhc2VfdGFnIDwtIGFzX3BocmFzZW1hY2hpbmUoZGYxJHVwb3MsIHR5cGUgPSAidXBvcyIpCiAgc3RhdHMxIDwtIGtleXdvcmRzX3BocmFzZXMoeCA9IGRmMSRwaHJhc2VfdGFnLCB0ZXJtID0gdG9sb3dlcihkZjEkdG9rZW4pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKEF8TikqTihQK0QqKEF8TikqTikqIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc19yZWdleCA9IFRSVUUsIGRldGFpbGVkID0gRkFMU0UpCiAgc3RhdHMxIDwtIHN1YnNldChzdGF0czEsIG5ncmFtID4gMSAmIGZyZXEgPiAzKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMxJGtleXdvcmQpKQogIAogIGRmMiRwaHJhc2VfdGFnIDwtIGFzX3BocmFzZW1hY2hpbmUoZGYyJHVwb3MsIHR5cGUgPSAidXBvcyIpCiAgc3RhdHMyIDwtIGtleXdvcmRzX3BocmFzZXMoeCA9IGRmMiRwaHJhc2VfdGFnLCB0ZXJtID0gdG9sb3dlcihkZjIkdG9rZW4pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKEF8TikqTihQK0QqKEF8TikqTikqIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc19yZWdleCA9IFRSVUUsIGRldGFpbGVkID0gRkFMU0UpCiAgc3RhdHMyIDwtIHN1YnNldChzdGF0czIsIG5ncmFtID4gMSAmIGZyZXEgPiAzKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleXdvcmQpKQogIAogIGMoYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMxLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIktleXdvcmRzIC0gc2ltcGxlIG5vdW4gcGhyYXNlczogQkVGT1JFIHZzIEFGVEVSIiwgeGxhYiA9ICJGcmVxdWVuY3kiKSwKICAgICAgYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMyLCAyMCksIGNvbCA9ICJza3libHVlIiwgCiAgICAgICAgICAgICAgIHhsYWIgPSAiRnJlcXVlbmN5IikpCn0KYGBgCgoKIyMgQmFyIENoYXJ0cyBmb3IgUGFydHMgb2YgU3BlZWNoIAoKYGBge3IgUE9TYmFyY2hhcnRzLCBlY2hvPUZBTFNFLCBmaWcud2lkdGg9OH0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpVUE9TX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpOT1VOU19iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKQURKX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpSQUtFX0tXX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpQV0lfYmFyY2hhcnQoeF9vZGQuYmVmb3JlLCB4X2V2ZW4uYWZ0ZXIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKClBPU19iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpgYGAKCgojIyBDb29jY3VyZW5jZXMKCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcud2lkdGg9Nn0KCkNPX09DX25vdW5fYWRqX3NhbWVfc2VudC5iZWZvcmUgPC0gZnVuY3Rpb24oZGYxKXsKICAKICBsaWJyYXJ5KGlncmFwaCkKICBsaWJyYXJ5KGdncmFwaCkKICBsaWJyYXJ5KGdncGxvdDIpCiAgCiAgY29vYyA8LSBjb29jY3VycmVuY2UoeCA9IHN1YnNldChkZjEsIHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgdGVybSA9ICJsZW1tYSIsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYygiZG9jX2lkIiwgInBhcmFncmFwaF9pZCIsICJzZW50ZW5jZV9pZCIpKQoKICB3b3JkbmV0d29yayA8LSBoZWFkKGNvb2MsIDYwKQogIHdvcmRuZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSh3b3JkbmV0d29yaykKICAKICBnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IGNvb2MsIGVkZ2VfYWxwaGEgPSBjb29jKSwgZWRnZV9jb2xvdXIgPSAicGluayIpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICAgIHRoZW1lX2dyYXBoKGJhc2VfZmFtaWx5ID0gIkFyaWFsIE5hcnJvdyIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicyh0aXRsZSA9ICJDb29jY3VycmVuY2VzIHdpdGhpbiBzZW50ZW5jZTogQkVGT1JFIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUiKQogIAp9CgpDT19PQ19ub3VuX2Fkal9zYW1lX3NlbnQuYWZ0ZXIgPC0gZnVuY3Rpb24oZGYyKXsKICAKICBsaWJyYXJ5KGlncmFwaCkKICBsaWJyYXJ5KGdncmFwaCkKICBsaWJyYXJ5KGdncGxvdDIpCiAgCiAgY29vYyA8LSBjb29jY3VycmVuY2UoeCA9IHN1YnNldChkZjIsIHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgdGVybSA9ICJsZW1tYSIsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYygiZG9jX2lkIiwgInBhcmFncmFwaF9pZCIsICJzZW50ZW5jZV9pZCIpKQoKICB3b3JkbmV0d29yayA8LSBoZWFkKGNvb2MsIDYwKQogIHdvcmRuZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSh3b3JkbmV0d29yaykKICAKICBnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IGNvb2MsIGVkZ2VfYWxwaGEgPSBjb29jKSwgZWRnZV9jb2xvdXIgPSAibGlnaHRncmVlbiIpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2JsdWUiLCBzaXplID0gNCkgKwogICAgdGhlbWVfZ3JhcGgoYmFzZV9mYW1pbHkgPSAiQXJpYWwgTmFycm93IikgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICBsYWJzKHRpdGxlID0gIkNvb2NjdXJyZW5jZXMgd2l0aGluIHNlbnRlbmNlOiBBRlRFUiIsIHN1YnRpdGxlID0gIk5vdW5zICYgQWRqZWN0aXZlIikKICAKfQoKCkNPX09DX25vdW5fYWRqX3NhbWVfc2VudC5iZWZvcmUoeF9vZGQuYmVmb3JlKQpDT19PQ19ub3VuX2Fkal9zYW1lX3NlbnQuYWZ0ZXIoeF9ldmVuLmFmdGVyKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKQ09fT0Nfbm91bl9hZGpfZm9sbG93aW5nLmJlZm9yZSA8LSBmdW5jdGlvbihkZil7CiAgY29vYyA8LSBjb29jY3VycmVuY2UoZGYkbGVtbWEsIHJlbGV2YW50ID0gZGYkdXBvcyAlaW4lIGMoIk5PVU4iLCAiQURKIiksIHNraXBncmFtID0gMSkKICBoZWFkKGNvb2MpCiAgCiAgd29yZG5ldHdvcmsgPC0gaGVhZChjb29jLCA2MCkKICB3b3JkbmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUod29yZG5ldHdvcmspCiAgZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSBjb29jLCBlZGdlX2FscGhhID0gY29vYyksIGVkZ2VfY29sb3VyID0gImxpZ2h0Z3JlZW4iKSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgY29sID0gImRhcmtncmVlbiIsIHNpemUgPSA0KSArCiAgICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgICBsYWJzKHRpdGxlID0gIldvcmRzIGZvbGxvd2luZyBvbmUgYW5vdGhlcjogQkVGT1JFIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUiKQp9CgpDT19PQ19ub3VuX2Fkal9mb2xsb3dpbmcuYWZ0ZXIgPC0gZnVuY3Rpb24oZGYpewogIGNvb2MgPC0gY29vY2N1cnJlbmNlKGRmJGxlbW1hLCByZWxldmFudCA9IGRmJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpLCBza2lwZ3JhbSA9IDEpCiAgaGVhZChjb29jKQogIAogIHdvcmRuZXR3b3JrIDwtIGhlYWQoY29vYywgNjApCiAgd29yZG5ldHdvcmsgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKHdvcmRuZXR3b3JrKQogIGdncmFwaCh3b3JkbmV0d29yaywgbGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJza3libHVlIikgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIGNvbCA9ICJkYXJrYmx1ZSIsIHNpemUgPSA0KSArCiAgICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgICBsYWJzKHRpdGxlID0gIldvcmRzIGZvbGxvd2luZyBvbmUgYW5vdGhlcjogQUZURVIiLCBzdWJ0aXRsZSA9ICJOb3VucyAmIEFkamVjdGl2ZSIpCn0KCgpDT19PQ19ub3VuX2Fkal9mb2xsb3dpbmcuYmVmb3JlKHhfb2RkLmJlZm9yZSkKQ09fT0Nfbm91bl9hZGpfZm9sbG93aW5nLmFmdGVyKHhfZXZlbi5hZnRlcikKCmBgYAoKCgojIyBDb29jY3VyZW5jZXMgKHBhcnQgMikKCmBgYHtyLCBlY2hvPUZBTFNFfQoKQ29ycnMgPC0gZnVuY3Rpb24oZGYpewogIGRmJGlkIDwtIHVuaXF1ZV9pZGVudGlmaWVyKGRmLCBmaWVsZHMgPSBjKCJzZW50ZW5jZV9pZCIsICJkb2NfaWQiKSkKICBkdG0gPC0gc3Vic2V0KGRmLCB1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSkKICBkdG0gPC0gZG9jdW1lbnRfdGVybV9mcmVxdWVuY2llcyhkdG0sIGRvY3VtZW50ID0gImlkIiwgdGVybSA9ICJsZW1tYSIpCiAgZHRtIDwtIGRvY3VtZW50X3Rlcm1fbWF0cml4KGR0bSkKICBkdG0gPC0gZHRtX3JlbW92ZV9sb3dmcmVxKGR0bSwgbWluZnJlcSA9IDUpCiAgdGVybWNvcnJlbGF0aW9ucyA8LSBkdG1fY29yKGR0bSkKICB5IDwtIGFzX2Nvb2NjdXJyZW5jZSh0ZXJtY29ycmVsYXRpb25zKQogIHkgPC0gc3Vic2V0KHksIHRlcm0xIDwgdGVybTIgJiBhYnMoY29vYykgPiAwLjIpCiAgeSA8LSB5W29yZGVyKGFicyh5JGNvb2MpLCBkZWNyZWFzaW5nID0gVFJVRSksIF0KICB5WzE6MjUsXQp9CgpgYGAKCmBgYHtyfQoKQ29ycnMoeF9vZGQuYmVmb3JlKQpDb3Jycyh4X2V2ZW4uYWZ0ZXIpCgpgYGAKCgojIEV4dHJlbShpc3QpIEZpZ2h0aW4nIFdvcmRzIE92ZXIgVGltZQpgYGB7cn0KbGlicmFyeSh0d2VlbnIpCgpUcmFuc2l0aW9uVGltZTIgPC0gZ2dwcm90bygKICAiVHJhbnNpdGlvblRpbWUyIiwKICBUcmFuc2l0aW9uVGltZSwKICBleHBhbmRfcGFuZWwgPSBmdW5jdGlvbiAoc2VsZiwgZGF0YSwgdHlwZSwgaWQsIG1hdGNoLCBlYXNlLCBlbnRlciwgZXhpdCwgcGFyYW1zLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXJfaW5kZXgpIHsKICAgIHJvd190aW1lIDwtIHNlbGYkZ2V0X3Jvd192YXJzKGRhdGEpCiAgICBpZiAoaXMubnVsbChyb3dfdGltZSkpIAogICAgICByZXR1cm4oZGF0YSkKICAgIGRhdGEkZ3JvdXAgPC0gcGFzdGUwKHJvd190aW1lJGJlZm9yZSwgcm93X3RpbWUkYWZ0ZXIpCiAgICB0aW1lIDwtIGFzLmludGVnZXIocm93X3RpbWUkdGltZSkKICAgIHN0YXRlcyA8LSBzcGxpdChkYXRhLCB0aW1lKQogICAgdGltZXMgPC0gYXMuaW50ZWdlcihuYW1lcyhzdGF0ZXMpKQogICAgbmZyYW1lcyA8LSBkaWZmKHRpbWVzKQogICAgbmZyYW1lc1sxXSA8LSBuZnJhbWVzWzFdICsgMQogICAgaWYgKHRpbWVzWzFdIDw9IDEpIHsKICAgICAgYWxsX2ZyYW1lcyA8LSBzdGF0ZXNbWzFdXQogICAgICBzdGF0ZXMgPC0gc3RhdGVzWy0xXQogICAgfQogICAgZWxzZSB7CiAgICAgIGFsbF9mcmFtZXMgPC0gZGF0YVswLCAsIGRyb3AgPSBGQUxTRV0KICAgICAgbmZyYW1lcyA8LSBjKHRpbWVzWzFdIC0gMSwgbmZyYW1lcykKICAgIH0KICAgIGlmICh0aW1lc1tsZW5ndGgodGltZXMpXSA8IHBhcmFtcyRuZnJhbWVzKSB7CiAgICAgIHN0YXRlcyA8LSBjKHN0YXRlcywgbGlzdChkYXRhWzAsICwgZHJvcCA9IEZBTFNFXSkpCiAgICAgIG5mcmFtZXMgPC0gYyhuZnJhbWVzLCBwYXJhbXMkbmZyYW1lcyAtIHRpbWVzW2xlbmd0aCh0aW1lcyldKQogICAgfQogICAgZm9yIChpIGluIHNlcV9hbG9uZyhzdGF0ZXMpKSB7CiAgICAgIGFsbF9mcmFtZXMgPC0gc3dpdGNoKHR5cGUsIHBvaW50ID0gdHdlZW5fc3RhdGUoYWxsX2ZyYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGVzW1tpXV0sIGVhc2UsIG5mcmFtZXNbaV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICEhaWQsIGVudGVyLCBleGl0KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGggPSB0cmFuc2Zvcm1fcGF0aChhbGxfZnJhbWVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlc1tbaV1dLCBlYXNlLCBuZnJhbWVzW2ldLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICEhaWQsIGVudGVyLCBleGl0LCBtYXRjaCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBwb2x5Z29uID0gdHJhbnNmb3JtX3BvbHlnb24oYWxsX2ZyYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZXNbW2ldXSwgZWFzZSwgbmZyYW1lc1tpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhIWlkLCBlbnRlciwgZXhpdCwgbWF0Y2gpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2YgPSB0cmFuc2Zvcm1fc2YoYWxsX2ZyYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlc1tbaV1dLCBlYXNlLCBuZnJhbWVzW2ldLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgISFpZCwgZW50ZXIsIGV4aXQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCh0eXBlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIGxheWVycyBub3QgY3VycmVudGx5IHN1cHBvcnRlZCBieSB0cmFuc2l0aW9uX3RpbWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWxsLiA9IEZBTFNFKSkKICAgIH0KICAgIHRydWVfZnJhbWUgPC0gc2VxKHRpbWVzWzFdLCB0aW1lc1tsZW5ndGgodGltZXMpXSkKICAgIGFsbF9mcmFtZXMgPC0gYWxsX2ZyYW1lc1sKICAgICAgYWxsX2ZyYW1lcyQuZnJhbWUgJWluJSAKICAgICAgICAjIHdoaWNoKHRydWVfZnJhbWUgPiAwICYgdHJ1ZV9mcmFtZSA8PSBwYXJhbXMkbmZyYW1lcyksCiAgICAgICAgdHJ1ZV9mcmFtZVt3aGljaCh0cnVlX2ZyYW1lID4gMCAmIHRydWVfZnJhbWUgPD0gcGFyYW1zJG5mcmFtZXMpXSwgIyB0d2VhayBsaW5lIEEKICAgICAgLCAKICAgICAgZHJvcCA9IEZBTFNFXQogICAgIyBhbGxfZnJhbWVzJC5mcmFtZSA8LSBhbGxfZnJhbWVzJC5mcmFtZSAtIG1pbihhbGxfZnJhbWVzJC5mcmFtZSkgKyAxICMgcmVtb3ZlIGxpbmUgQgogICAgYWxsX2ZyYW1lcyRncm91cCA8LSBwYXN0ZTAoYWxsX2ZyYW1lcyRncm91cCwgIjwiLCBhbGxfZnJhbWVzJC5mcmFtZSwgIj4iKQogICAgYWxsX2ZyYW1lcyQuZnJhbWUgPC0gTlVMTAogICAgYWxsX2ZyYW1lcwogIH0pCgp0cmFuc2l0aW9uX3RpbWUyIDwtIGZ1bmN0aW9uICh0aW1lLCByYW5nZSA9IE5VTEwpIHsKICB0aW1lX3F1byA8LSBlbnF1byh0aW1lKQogIGdnYW5pbWF0ZTo6OnJlcXVpcmVfcXVvKHRpbWVfcXVvLCAidGltZSIpCiAgZ2dwcm90byhOVUxMLCBUcmFuc2l0aW9uVGltZTIsIAogICAgICAgICAgcGFyYW1zID0gbGlzdCh0aW1lX3F1byA9IHRpbWVfcXVvLCByYW5nZSA9IHJhbmdlKSkKfQpgYGAKCmBgYHtyIGV4dHJhX2xvYWRzX29kZF9iZWZvcmUsIGVjaG89RkFMU0V9CmxpYnJhcnkoZ2dyYXBoKQpsaWJyYXJ5KGdnZm9yY2UpCmxpYnJhcnkoZ2dhbmltYXRlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KGFuaW1hdGlvbikKbGlicmFyeShsdWJyaWRhdGUpCgoKcmVzdWx0czwtbWVyZ2UoeD14LHk9ZXh0cmVtX0FQLmRmbS5sb25nLCBieS54PSdkb2NfaWQnLCAgYnkueSA9IDAgICxhbGwueD1UUlVFKQpyZXN1bHRzX29kZC5iZWZvcmUgPC0gcmVzdWx0c1tyZXN1bHRzJGRvY19pZCAlJSAyID09IDEsXQpyZXN1bHRzX2V2ZW4uYWZ0ZXIgPC1yZXN1bHRzW3Jlc3VsdHMkZG9jX2lkICUlIDIgPT0gMCwgXQoKY29vY195ZWFyPC0gZGF0YS5mcmFtZSgpCgpmb3IoeSBpbiB1bmlxdWUocmVzdWx0c19vZGQuYmVmb3JlJHB1YnllYXIpKXsKICAjIHByaW50KHkpCiAgY29vYyA8LSBjb29jY3VycmVuY2UoeCA9IHN1YnNldChmaWx0ZXIocmVzdWx0c19vZGQuYmVmb3JlLCBwdWJ5ZWFyID09IHkpLCB1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSksIAogICAgICAgICAgICAgICAgICAgICAgIHRlcm0gPSAibGVtbWEiLCAKICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGMoImRvY19pZCIsICJwYXJhZ3JhcGhfaWQiLCAic2VudGVuY2VfaWQiKSkKICBjb29jJHllYXIgPC0geQogIGNvb2M8LSBoZWFkKGNvb2MsIDE0KQogIGNvb2NfeWVhciA8LSByYmluZChjb29jX3llYXIsIGNvb2MpCn0KCndvcmRuZXR3b3JrIDwtIGNvb2NfeWVhcgoKZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJwaW5rIikgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyBmYWNldF93cmFwX3BhZ2luYXRlKH55ZWFyKSsKICBzY2FsZV9hbHBoYV9pZGVudGl0eSgpKwogIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEJFRk9SRSIsIHN1YnRpdGxlID0gIk5vdW5zICYgQWRqZWN0aXZlIHtmcmFtZV90aW1lfSIpKwogIHRyYW5zaXRpb25fdGltZTIoeWVhcikKICBlYXNlX2FlcygnbGluZWFyJykKCiMgcGxvdChwKQojIHAKCiMgbGFzdF9hbmltYXRpb24oKQoKYGBgCmBgYHtyIGV4dHJhX2xvYWRzX2V2ZW5fYWZ0ZXIsIGVjaG89RkFMU0V9Cgpjb29jX3llYXI8LSBkYXRhLmZyYW1lKCkKCmZvcih5IGluIHVuaXF1ZShyZXN1bHRzX2V2ZW4uYWZ0ZXIkcHVieWVhcikpewogICMgcHJpbnQoeSkKICBjb29jIDwtIGNvb2NjdXJyZW5jZSh4ID0gc3Vic2V0KGZpbHRlcihyZXN1bHRzX2V2ZW4uYWZ0ZXIsIHB1YnllYXIgPT0geSksIHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgdGVybSA9ICJsZW1tYSIsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYygiZG9jX2lkIiwgInBhcmFncmFwaF9pZCIsICJzZW50ZW5jZV9pZCIpKQogIGNvb2MkeWVhciA8LSB5CiAgY29vYzwtIGhlYWQoY29vYywgMTQpCiAgY29vY195ZWFyIDwtIHJiaW5kKGNvb2NfeWVhciwgY29vYykKfQoKCndvcmRuZXR3b3JrIDwtIGNvb2NfeWVhcgoKZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJwaW5rIikgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyBmYWNldF93cmFwX3BhZ2luYXRlKH55ZWFyKSsKICBzY2FsZV9hbHBoYV9pZGVudGl0eSgpKwogIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEFGVEVSIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUge2ZyYW1lX3RpbWV9IikrCiAgdHJhbnNpdGlvbl90aW1lMih5ZWFyKQogIGVhc2VfYWVzKCdsaW5lYXInKQoKIyBwbG90KHAyKQojIHAyCgojIGxhc3RfYW5pbWF0aW9uKCkKCmBgYAoKYGBge3IgY29vYzJfYmVmb3JlLCBlY2hvPUZBTFNFfQoKY29vYzJfeWVhcjwtIGRhdGEuZnJhbWUoKQoKZm9yKHkgaW4gdW5pcXVlKHJlc3VsdHNfb2RkLmJlZm9yZSRwdWJ5ZWFyKSl7CiAgIyBwcmludCh5KQogIGE8LSBmaWx0ZXIocmVzdWx0c19vZGQuYmVmb3JlLCBwdWJ5ZWFyID09IHkpCiAgCiAgY29vYyA8LSBjb29jY3VycmVuY2UoYSRsZW1tYSwgcmVsZXZhbnQgPSBhJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpLCBza2lwZ3JhbSA9IDEpCiAgY29vYyR5ZWFyIDwtIHkKICBjb29jPC0gaGVhZChjb29jLCAyNSkKICBjb29jMl95ZWFyIDwtIHJiaW5kKGNvb2MyX3llYXIsIGNvb2MpCn0KCgp3b3JkbmV0d29yayA8LSBjb29jMl95ZWFyCgpnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSBjb29jLCBlZGdlX2FscGhhID0gY29vYyksIGVkZ2VfY29sb3VyID0gInBpbmsiKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIGNvbCA9ICJkYXJrZ3JlZW4iLCBzaXplID0gNCkgKwogIHRoZW1lX2dyYXBoKGJhc2VfZmFtaWx5ID0gIkFyaWFsIE5hcnJvdyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAjIGZhY2V0X3dyYXBfcGFnaW5hdGUofnllYXIpKwogIHNjYWxlX2FscGhhX2lkZW50aXR5KCkrCiAgbGFicyh0aXRsZSA9ICJDb29jY3VycmVuY2VzIHdpdGhpbiBzZW50ZW5jZTogQkVGT1JFIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUge2ZyYW1lX3RpbWV9IikrCiAgdHJhbnNpdGlvbl90aW1lMih5ZWFyKQogIGVhc2VfYWVzKCdsaW5lYXInKQoKIyBwbG90KHAzKQojIHAzCgojIGxhc3RfYW5pbWF0aW9uKCkKCmBgYApgYGB7ciBjb29jMl9hZnRlciwgZWNobz1GQUxTRX0KCmNvb2MyX3llYXI8LSBkYXRhLmZyYW1lKCkKCmZvcih5IGluIHVuaXF1ZShyZXN1bHRzX2V2ZW4uYWZ0ZXIkcHVieWVhcikpewogICMgcHJpbnQoeSkKICBhPC0gZmlsdGVyKHJlc3VsdHNfZXZlbi5hZnRlciwgcHVieWVhciA9PSB5KQogIAogIGNvb2MgPC0gY29vY2N1cnJlbmNlKGEkbGVtbWEsIHJlbGV2YW50ID0gYSR1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSwgc2tpcGdyYW0gPSAxKQogIGNvb2MkeWVhciA8LSB5CiAgY29vYzwtIGhlYWQoY29vYywgMTIpCiAgY29vYzJfeWVhciA8LSByYmluZChjb29jMl95ZWFyLCBjb29jKQp9CgoKd29yZG5ldHdvcmsgPC0gY29vYzJfeWVhcgoKZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJwaW5rIikgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyBmYWNldF93cmFwX3BhZ2luYXRlKH55ZWFyKSsKICBzY2FsZV9hbHBoYV9pZGVudGl0eSgpKwogIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEFGVEVSIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUge2ZyYW1lX3RpbWV9IikrCiAgdHJhbnNpdGlvbl90aW1lMih5ZWFyKQogIGVhc2VfYWVzKCdsaW5lYXInKQoKIyBwbG90KHA0KQojIHA0CiMgbGFzdF9hbmltYXRpb24oKQoKYGBgCgoKCgpgYGB7ciBmaW5hbCwgZWNobz1GQUxTRX0KCnJtKGxpc3Q9bHMoKSkKCmBgYAoKCgoKCgoKCltob21lXShodHRwczovL2JyZWdyZWVuLmdpdGh1Yi5pby8pCg==